package qc.module.qms.dps.consumer;

import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import qc.common.core.constants.QmsMQConstant;
import qc.common.core.enums.qms.QmsDataFlowOperateTypeEnum;
import qc.common.core.enums.qms.QmsPointTimeSegmentEnum;
import qc.common.core.enums.qms.QmsRawDataCalcFlagEnum;
import qc.common.core.exception.QCPromptException;
import qc.common.core.utils.LocalDateTimeUtil;
import qc.common.core.utils.QmsTimeUtil;
import qc.module.platform.dto.db.DBConnectionDto;
import qc.module.qms.algorithm.NumericCalc.dto.QmsNumericCalcUseMethod;
import qc.module.qms.dps.RestTemplatePlatform;
import qc.module.qms.dto.calc.QmsPointDataCalcResultDto;
import qc.module.qms.dto.calc.QmsPointDataCalcSaveResultDto;
import qc.module.qms.dto.mq.QmsMqRawDataMessageDto;
import qc.module.qms.dto.pointdata.QmsPointDataManageResultDto;
import qc.module.qms.dto.rawdata.QmsRawDataDto;
import qc.module.qms.dto.rawdata.QmsRawNumericDataDto;
import qc.module.qms.entity.QmsPoint;
import qc.module.qms.entity.QmsRawdataMapElement;
import qc.module.qms.entity.QmsRawdataMapStation;
import qc.module.qms.service.QmsBasicConfigCacheGetService;
import qc.module.qms.service.calc.QmsNumericCalcGetService;
import qc.module.qms.service.pointdata.QmsPointDataCalcService;
import qc.module.qms.service.pointdata.QmsPointDataLatestService;
import qc.module.qms.service.producer.QmsDataFlowLogProducer;
import qc.module.qms.service.rawdata.QmsRawDataMapGetService;
import qc.module.qms.service.rawdata.QmsRawDataRecordService;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 原始数据计算Consumer
 *
 * @author QuCheng Tech
 * @since 2025/8/12
 */
@Component
@RocketMQMessageListener(
        topic = QmsMQConstant.MQ_RAWDATA_TOPIC,
        consumerGroup = QmsMQConstant.MQ_RAWDATA_CONSUMER_CALC_GROUP
)
public class RawDataCalcConsumer implements RocketMQListener<QmsMqRawDataMessageDto> {
    private static final Logger logger = LoggerFactory.getLogger(RawDataCalcConsumer.class);

    //模块名称，用于在日志或显示中统一使用
    private static final String moduleName = "原始采集数据消息数值计算";

    @Autowired
    private QmsRawDataRecordService rawDataRecordService;

    @Autowired
    private QmsDataFlowLogProducer dataFlowLogProducer;

    @Autowired
    private QmsBasicConfigCacheGetService basicConfigCacheGetService;

    @Autowired
    private QmsRawDataMapGetService rawDataMapGetService;

    @Autowired
    private QmsNumericCalcGetService numericCalcGetService;

    @Autowired
    private QmsPointDataCalcService pointDataCalcService;

    @Autowired
    private QmsPointDataLatestService pointDataLatestService;

    @Autowired
    private RestTemplatePlatform restTemplatePlatform;

    /**
     * 维护一个数据库表编码和数据库连接信息对应关系集合，如果接收到的原始数据库表编码没有数据库连接信息调用platform中的接口获取
     */
    private static HashMap<String, DBConnectionDto> tableCodeConnectionMap;

    @Override
    public void onMessage(QmsMqRawDataMessageDto message) {
        logger.debug("onMessage " + moduleName);

        LocalDateTime now = LocalDateTimeUtil.getNow();
        //当前数据流程节点的操作类型：如果不对应点号设置为处理原始数据，如果对应点号设置为根据原始数据进行点号数据计算
        QmsDataFlowOperateTypeEnum processRawDataOptype = QmsDataFlowOperateTypeEnum.PROCESS_RAW_DATA;

        //接收到的消息有效性验证
        String validMessageResult = null;
        if (message == null) {
            validMessageResult = "原始数据消息对象为空";
        } else {
            if (StringUtils.isBlank(message.getTablecode())) {
                validMessageResult = "原始数据消息中数据库表编码为空";
            } else {
                if (message.getDatas() == null || message.getDatas().size() < 0x1) {
                    validMessageResult = "原始数据消息中数据集合为空或数据数量为0";
                }
            }
        }
        //判断如果接收到的消息有效性验证未通过，进行错误日志记录
        if (StringUtils.isNotBlank(validMessageResult)) {
            logger.error("onMessage " + moduleName + "，" + validMessageResult);

            //数据处理流程日志记录
            dataFlowLogProducer.send(null, message.getFlowid(), message.getNodeid(), processRawDataOptype, false,
                    now, null, false, validMessageResult, null, QmsPointTimeSegmentEnum.UN_DEFINE, null, null);

            return;
        }

        String tableCode = message.getTablecode();
        //一条消息是按数据库表进行划分好的数据，一条消息是同一个数据库表中的数据，一条消息中有多条数据，每条数据中可以包含多个采集要素值
        logger.debug("onMessage " + moduleName + "，数据库表[" + tableCode + "]原始数据条数[" + message.getDatas().size() + "]");
        //同一个站点的同一个采集要素的计算方法相同，在此根据站点进行合并计算（同一个站点的同一个采集要素调用一次计算方法）            
        //一个站点的一个采集要素对应一个点号，一个点号的多个时间点采集数据集合计算一次，数据流程日志也记录一条
        List<String> rawStcds = message.getDatas().stream().filter(p -> StringUtils.isNotBlank(p.getStcd())).map(p -> p.getStcd()).distinct().collect(Collectors.toList());
        if (rawStcds == null || rawStcds.size() < 0x1) {
            //没有任何有效的站点编码集合，进行日志记录；
            //此种情况不可能发生，在前面接收原始数据时已经对stcd进行验证
            validMessageResult = "去重后的站点集合为空";

            logger.error("onMessage " + moduleName + "，" + validMessageResult);

            //数据处理流程日志记录
            dataFlowLogProducer.send(null, message.getFlowid(), message.getNodeid(), processRawDataOptype, false,
                    now, null, false, validMessageResult, null, QmsPointTimeSegmentEnum.UN_DEFINE, null, null);

            return;
        }

        //根据数据库表编码获取对应的数据库连接信息
        DBConnectionDto dbConnection = null;
        try {
            dbConnection = this.getTableConnection(tableCode);
        } catch (QCPromptException e) {
            logger.error("onMessage " + moduleName + "，数据库表[" + tableCode + "]获取对应数据库连接信息异常，" + e.getMessage());
        }

        logger.info("onMessage " + moduleName + "，共有不同站点[" + rawStcds.size() + "]个");
        for (String rawStcd : rawStcds) {
            logger.debug("onMessage 逐个站点原始数据计算处理，开始筛选站点编码[" + rawStcd + "]的原始数据");
            //根据站点编码筛选原始数据
            List<QmsRawDataDto> filterByStcdRawDatas = message.getDatas().stream().filter(p -> StringUtils.equalsIgnoreCase(p.getStcd(), rawStcd)).collect(Collectors.toList());
            //此处不需要判断集合是否为空，因为站点编码是用同一个集合筛选出来的
            //根据数据库表名称+站点编码查找对应的QMS系统中的站点编码
            QmsRawdataMapStation station = rawDataMapGetService.getRawDataMapStationByRawStcd(tableCode, rawStcd);
            //判断站点对应关系是否存在，状态是否为禁用
            String validStationMapResult = null;
            if (station == null) {
                validStationMapResult = "不存在站点对应关系";
            } else {
                if (station.getIsdisable() == true) {
                    validStationMapResult = "站点对应关系为禁用状态";
                } else {
                    if (StringUtils.isBlank(station.getStcd()))
                        validStationMapResult = "站点对应关系有效，对应系统站点编码设置错误，系统站点编码为空";
                }
            }
            if (StringUtils.isNotBlank(validStationMapResult)) {
                String errorMsg = "原始数据站点编码[" + rawStcd + "]，" + validStationMapResult;
                logger.error("onMessage " + errorMsg);
                //当前站点如果映射不存在，无法进行该站点编码的数据计算处理
                rawDataRecordService.setFlag(tableCode, null, filterByStcdRawDatas, QmsRawDataCalcFlagEnum.NO_MAP_STATION, dbConnection);

                //进行数据流程日志记录
                dataFlowLogProducer.send(null, message.getFlowid(), message.getNodeid(), processRawDataOptype, false,
                        now, null, false, errorMsg, null, QmsPointTimeSegmentEnum.UN_DEFINE, null, null);
            } else {
                //获取对应的系统站点编码
                String stcd = station.getStcd();
                logger.debug("onMessage 原始数据站点编码[" + rawStcd + "]对应的系统站点编码[" + stcd + "]");
                //映射关系不为空，遍历站点的逐条数据进行处理（每条数据中有多个采集要素）
                //不能直接遍历原始数据，需要对原始数据不同采集要素再进行合并；同一个要素的不同时标数据使用一次计算；
                List<QmsRawNumericDataDto> allNumericRawDatas = new ArrayList<>();
                //记录当前站点原始数据集合中的所有列名（每列对应一种采集要素）
                List<String> columnCodes = new ArrayList<>();
                logger.debug("onMessage 原始数据站点编码[" + rawStcd + "]共有原始数据[" + filterByStcdRawDatas.size() + "]条");
                for (QmsRawDataDto rawdata : filterByStcdRawDatas) {
                    Map<String, String> rawDataElements = rawdata.getElements();
                    if (rawDataElements != null && rawDataElements.size() > 0x0) {
                        int elIndex = 0x0;

                        for (Map.Entry<String, String> entry : rawDataElements.entrySet()) {
                            elIndex++;
                            //获取每项中的key作为要素编码，value作为要素值
                            String key = null;
                            double value = Double.NaN;
                            //判断采集要素无效的提示信息
                            String errorMsg = null;
                            if (entry == null) {
                                errorMsg = "第" + elIndex + "个采集要素信息为空；";
                            } else {
                                if (StringUtils.isBlank(entry.getKey())) {
                                    errorMsg = "第" + elIndex + "个采集要素键为空；";
                                } else {
                                    //获取采集要素编码/名称
                                    key = entry.getKey();
                                    if (StringUtils.isBlank(entry.getValue())) {
                                        errorMsg = "第" + elIndex + "个采集要素值为空；";
                                    } else {
                                        //此处还需要根据key判断对应的采集要素数值类型，如果是布尔、整型、浮点型才进行数值转换判断
                                        //判断采集要素数值类型应在原始数据消费者中进行判断
                                        //添加到采集要素及数据值集合中
                                        //elements.put(key, value);
                                        try {
                                            double dv = Double.parseDouble(entry.getValue());
                                            if (Double.isNaN(dv)) {
                                                errorMsg = "第" + elIndex + "个采集要素值" + entry.getValue() + "无法转换为有效的数值；";
                                            } else {
                                                value = dv;
                                            }
                                        } catch (NumberFormatException ex) {
                                            errorMsg = "第" + elIndex + "个采集要素值" + entry.getValue() + "无法转换为有效的数值；";
                                        }
                                    }
                                }
                            }
                            //如果采集要素键不为空、数值有效，加入到需要处理的数据集合中
                            if (StringUtils.isNotBlank(key) && Double.isNaN(value) == false) {
                                //判断当前站点采集要素集合中是否有当前采集要素，如果没有则进行添加
                                if (columnCodes.size() < 0x1 || columnCodes.contains(key) == false)
                                    columnCodes.add(key);

                                QmsRawNumericDataDto numericData = new QmsRawNumericDataDto();
                                numericData.setId(rawdata.getId());
                                numericData.setStcd(rawdata.getStcd());
                                numericData.setTm(rawdata.getTm());
                                numericData.setChannel(rawdata.getChannel());

                                numericData.setElement(key);
                                numericData.setValue(value);

                                allNumericRawDatas.add(numericData);
                            }
                        }
                    }
                }
                //判断最终的数值数据集合是否为空，不为空再进行处理
                if (columnCodes == null || columnCodes.size() < 0x1 || allNumericRawDatas == null || allNumericRawDatas.size() < 0x1) {
                    String errorMsg = "原始数据站点编码[" + rawStcd + "]，没有任何数值数据或采集要素集合";
                    logger.error("onMessage " + errorMsg);
                    //当前站点的原始数据中无任何有效的数值数据
                    rawDataRecordService.setFlag(tableCode, null, filterByStcdRawDatas, QmsRawDataCalcFlagEnum.NOT_NUMERIC, dbConnection);

                    //进行数据流程日志记录
                    dataFlowLogProducer.send(null, message.getFlowid(), message.getNodeid(), processRawDataOptype, false,
                            now, null, false, errorMsg, null, QmsPointTimeSegmentEnum.UN_DEFINE, null, null);
                } else {
                    logger.debug("onMessage 原始数据站点编码[" + rawStcd + "]共有不同列名（采集要素）[" + columnCodes.size() + "]个");
                    logger.debug("onMessage 原始数据站点编码[" + rawStcd + "]共有数值类型数据[" + allNumericRawDatas.size() + "]条");
                    for (String rawColumnCode : columnCodes) {
                        logger.debug("onMessage 数值类型原始数据计算，原始数据站点编码[" + rawStcd + "]，列名[" + rawColumnCode + "]");
                        //先根据原始数据站点编码和原始数据列名筛选数值数据，如果筛选出的数值数据集合为空则不需要验证对应关系和数据处理
                        //根据站点编码和采集要素筛选出当前点号的原始数据集合
                        List<QmsRawNumericDataDto> pointRawDatas = allNumericRawDatas.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getStcd(), rawStcd) && StringUtils.equalsIgnoreCase(p.getElement(), rawColumnCode)).collect(Collectors.toList());
                        if (pointRawDatas == null || pointRawDatas.size() < 0x1) {
                            //根据stcd和ele筛选出的原始数据为空，此时不需要进行日志记录
                            logger.warn("onMessage 数值类型原始数据计算，原始数据站点编码[" + rawStcd + "]，列名[" + rawColumnCode + "]，筛选出的原始数值数据为空");
                        } else {
                            //根据数据库表编码+原始数据列名获取对应的采集要素
                            //在根据站点编码+采集要素获取点号
                            QmsRawdataMapElement element = rawDataMapGetService.getRawdataMapElementByRawColumn(tableCode, rawColumnCode);
                            //验证对应采集要素信息是否为空，是否禁用
                            String validElementMapResult = null;
                            if (element == null) {
                                validElementMapResult = "不存在原始数据列名与采集要素对应关系";
                            } else {
                                if (element.getIsdisable() == true) {
                                    validElementMapResult = "原始数据列名与采集要素对应关系为禁用状态";
                                } else {
                                    if (StringUtils.isBlank(element.getElecode()))
                                        validElementMapResult = "原始数据列名与采集要素对应关系有效，对应采集要素编码设置错误，采集要素为空";
                                }
                            }
                            if (StringUtils.isNotBlank(validElementMapResult)) {
                                String errorMsg = "原始数据站点编码[" + rawStcd + "]，列名[" + rawColumnCode + "]" + validElementMapResult;
                                logger.error("onMessage 数值类型原始数据计算，" + errorMsg);
                                //如果没有对应的采集要素映射关系，修改原始数据中的处理标记和处理时间
                                rawDataRecordService.setFlag(tableCode, rawColumnCode, filterByStcdRawDatas, QmsRawDataCalcFlagEnum.NO_MAP_ELEMENT, dbConnection);

                                //进行数据流程日志记录
                                dataFlowLogProducer.send(null, message.getFlowid(), message.getNodeid(), processRawDataOptype, false,
                                        now, null, false, errorMsg + validElementMapResult, null, QmsPointTimeSegmentEnum.UN_DEFINE, null, null);
                            } else {
                                //采集要素对应关系有效
                                String eleCode = element.getElecode();
                                QmsPointTimeSegmentEnum pointtmseg = element.getTmseg();//点号的时段类型仅在保存点号时使用，不作为获取对应点号的输入
                                String ext = element.getExt();//获取对应关系中的测点顺序号
                                logger.debug("onMessage 数值类型原始数据计算，原始数据站点编码[" + rawStcd + "]，列名[" + rawColumnCode
                                        + "]，对应的监测要素编码[" + eleCode + "]，时段类型[" + pointtmseg.toString() + "]，扩展标记[" + ext + "]");
                                //获取对应要素中设置的是否为累计值，如果为累计值并且点号配置的计算方法为累计值求差值需要查询前一条最近原始数据传入计算方法
                                boolean eleIsTotal = false;
                                if (element.getIstotal() != null && element.getIstotal().booleanValue() == true)
                                    eleIsTotal = true;
                                //根据站点编码+采集要素编码获取对应的点号，如果获取到多个在日志中进行warn，获取默认一个点号继续进行处理
                                QmsPoint point = basicConfigCacheGetService.getPointByStcdAndElementCode(stcd, eleCode, ext);
                                //验证点号信息是否为空
                                if (point == null) {
                                    //记录点号信息为空错误
                                    String errorMsg = "原始数据站点编码[" + rawStcd + "]，列名[" + rawColumnCode + "]，不存在任何点号映射关系";
                                    logger.error("onMessage 数值类型原始数据计算，" + errorMsg);
                                    //如果没有对应的映射关系，修改原始数据中的处理标记和处理时间
                                    rawDataRecordService.setFlag(tableCode, rawColumnCode, filterByStcdRawDatas, QmsRawDataCalcFlagEnum.NO_MAP_POINT, dbConnection);

                                    //进行数据流程日志记录
                                    dataFlowLogProducer.send(null, message.getFlowid(), message.getNodeid(), processRawDataOptype, false,
                                            now, null, false, errorMsg, null, QmsPointTimeSegmentEnum.UN_DEFINE, null, null);
                                } else {
                                    String pointid = point.getPointid();
                                    //原始数据有对应的点号，设置当前处理原始数据流程节点操作类型为根据原始数据计算点号数据
                                    processRawDataOptype = QmsDataFlowOperateTypeEnum.CALC_POINT_DATA_BY_RAW_DATA;

                                    //原始数据有对应点号数据，在此更新点号数据最新状态中的原始数据字段信息
                                    Optional<QmsRawNumericDataDto> maxTmRawData = pointRawDatas.stream().max(Comparator.comparing(QmsRawNumericDataDto::getTm));
                                    pointDataLatestService.updateRawData(pointid, pointtmseg, maxTmRawData.get().getTm(), maxTmRawData.get().getValue(), false);

                                    //获取计算方法，判断计算方法是否有效
                                    QmsNumericCalcUseMethod calcMethod = numericCalcGetService.getPointValidCalcUseMethod(point, pointtmseg);
                                    if (calcMethod == null) {
                                        //记录点号计算方法为空错误
                                        String errorMsg = "原始数据站点编码[" + rawStcd + "]，列名[" + rawColumnCode + "]，对应点号编码[" + pointid
                                                + "]，时段类型[" + pointtmseg + "]，无有效的计算方法，无法进行数值计算";
                                        logger.error("onMessage 数值类型原始数据计算，" + errorMsg);
                                        //如果没有对应的映射关系，修改原始数据中的处理标记和处理时间
                                        rawDataRecordService.setFlag(tableCode, rawColumnCode, filterByStcdRawDatas, QmsRawDataCalcFlagEnum.NO_CALC_METHOD, dbConnection);

                                        //进行数据流程日志记录
                                        dataFlowLogProducer.send(null, message.getFlowid(), message.getNodeid(), processRawDataOptype, false, now, null, false, errorMsg,
                                                pointid, pointtmseg, null, null);
                                    } else {
                                        //对原始数据的时间进行规整，并按规整后的时间去重
                                        Map<LocalDateTime, Double> regularTimeRawDatas = new HashMap<>();
                                        //不能直接从原始数值数据List映射为时间和数值的键值对，可能存在相同的采集时间有多条数据（数值可能相同也可能不同），相同的时间点仅保存最新数据值
                                        //stream方法中未找到按时间去重方法，使用遍历逐个元素方法实现
                                        //Map<Date, Double> calcRawDatas = pointRawDatas.stream().collect(Collectors.toMap(p -> p.getTm(), p -> p.getValue()));
                                        //调用计算模块，获取计算结果；点号数据中只有数据质量，不关注原始数据来源通道；实际点号数据与原始数据也不是一一对应关系
                                        //规整数据时标后的起止时间，需要作为计算方法的传入参数
                                        LocalDateTime regularBeginTime = null;
                                        LocalDateTime regularEndTime = null;
                                        //判断计算方法和对应要素是否为累计值，确定是否要查询原始数据
                                        if (eleIsTotal == true) {
                                            //如果采集要素是累计值，本次触发计算的数据可能不是起止时间内的全部数据，但是由于其中一个时间点数据的变化会导致当前时间点和下一个时间点数值需要重新计算（计算后的数值没有变化时在保存点号时再进行去重处理）
                                            //此处传入点号数值计算方法中的原始数据需要重新查询：重新触发的起止时间段内的全部数据进行计算处理
                                            //获取原始数据中的数据时间最小和最大值
                                            Optional<QmsRawNumericDataDto> minTmRawData = pointRawDatas.stream().min(Comparator.comparing(QmsRawNumericDataDto::getTm));
                                            LocalDateTime rawDataBeginTime = minTmRawData.get().getTm();
                                            LocalDateTime rawDataEndTime = maxTmRawData.get().getTm();
                                            logger.debug("onMessage 数值类型原始数据计算，原始数据站点编码[" + rawStcd + "]，列名[" + rawColumnCode + "]，对应点号编码["
                                                    + pointid + "]，对应点号时段类型[" + pointtmseg + "]，本次处理的监测要素为累计值，需要在原始采集数据库中查询起止时间段[" +
                                                    LocalDateTimeUtil.formatDateTime(rawDataBeginTime) + "]-[" + LocalDateTimeUtil.formatDateTime(rawDataEndTime) + "]的全部数据。");
                                            Map<LocalDateTime, Double> getTimeRangeRawDatas = rawDataRecordService.getStationElementRawDatas(tableCode, rawStcd, rawColumnCode, rawDataBeginTime, rawDataEndTime);
                                            //从原始数据库中查询的数据可能会为空，因为原始数据通过MQ进行数据写入数据库处理，有可能没有写入数据库
                                            //在没有写入数据库时使用本次触发消息中的原始数据集合；如果查询出的数据数量与触发消息数据数量相同也不需要使用查询出的数据
                                            if (getTimeRangeRawDatas != null && getTimeRangeRawDatas.size() > pointRawDatas.size()) {
                                                regularTimeRawDatas = new HashMap<>();
                                                //按采集时间进行去重处理，先进行时间规整后再按规整后的数据时标进行去重处理
                                                for (Map.Entry<LocalDateTime, Double> entry : getTimeRangeRawDatas.entrySet()) {
                                                    //数据时标时间规整处理
                                                    LocalDateTime regularTm = QmsTimeUtil.getRegularTime(entry.getKey(), element.getRegularsecond());
                                                    if (regularTimeRawDatas.containsKey(regularTm))
                                                        regularTimeRawDatas.replace(regularTm, entry.getValue());
                                                    else
                                                        regularTimeRawDatas.put(regularTm, entry.getValue());

                                                    //对规整后的起止数据时标进行赋值
                                                    if (regularBeginTime == null || regularBeginTime.isAfter(regularTm))
                                                        regularBeginTime = regularTm;
                                                    if (regularEndTime == null || regularEndTime.isBefore(regularTm))
                                                        regularEndTime = regularTm;
                                                }
                                            }
                                        } else {
                                            //不是累计值数据，不需要查询全部的原始数据，直接使用触发消息的原始数据按采集时间进行去重处理，先进行时间规整后再按规整后的数据时标进行去重处理
                                            for (QmsRawNumericDataDto rnd : pointRawDatas) {
                                                //数据时标时间规整处理
                                                LocalDateTime regularTm = QmsTimeUtil.getRegularTime(rnd.getTm(), element.getRegularsecond());
                                                if (regularTimeRawDatas.containsKey(regularTm))
                                                    regularTimeRawDatas.replace(regularTm, rnd.getValue());
                                                else
                                                    regularTimeRawDatas.put(regularTm, rnd.getValue());

                                                //对规整后的起止数据时标进行赋值
                                                if (regularBeginTime == null || regularBeginTime.isAfter(regularTm))
                                                    regularBeginTime = regularTm;
                                                if (regularEndTime == null || regularEndTime.isBefore(regularTm))
                                                    regularEndTime = regularTm;

                                                logger.debug("原始数值数据，" + QmsTimeUtil.format(regularTm, pointtmseg) + "\t" + rnd.getValue());
                                            }
                                        }

                                        //调用计算方法
                                        QmsPointDataCalcSaveResultDto calcSaveResultDto = pointDataCalcService.calcRawDatas(point, pointtmseg, calcMethod, regularBeginTime, regularEndTime, processRawDataOptype,
                                                false, message.getFlowid(), message.getNodeid(), regularTimeRawDatas, tableCode, rawStcd, rawColumnCode, filterByStcdRawDatas, dbConnection);
                                        //在pointDataCalcService.calc方法中已经完成日志记录、流程日志消息发送、原始数据处理标记修改
                                        //此处可以不对处理结果进行判断和输出显示
                                        if (calcSaveResultDto == null) {
                                            //计算和保存结果为null
                                            logger.error("onMessage 数值类型原始数据计算，原始数据站点编码[" + rawStcd + "]，列名[" + rawColumnCode + "]，对应点号编码[" + pointid
                                                    + "]，时段类型[" + pointtmseg + "]，计算时间段[" + QmsTimeUtil.format(regularBeginTime, pointtmseg) + "]-[" + QmsTimeUtil.format(regularEndTime, pointtmseg)
                                                    + "]，点号计算和保存的结果对象为null");
                                        } else {
                                            if (calcSaveResultDto.getCalcResult() == null) {
                                                //计算结果为null
                                                logger.error("onMessage 数值类型原始数据计算，原始数据站点编码[" + rawStcd + "]，列名[" + rawColumnCode + "]，对应点号编码[" + pointid
                                                        + "]，时段类型[" + pointtmseg + "]，计算时间段[" + QmsTimeUtil.format(regularBeginTime, pointtmseg) + "]-[" + QmsTimeUtil.format(regularEndTime, pointtmseg)
                                                        + "]，点号计算结果对象为null");
                                            } else {
                                                QmsPointDataCalcResultDto calcResult = calcSaveResultDto.getCalcResult();
                                                if (calcResult.isSuccess() == false) {
                                                    //计算失败
                                                    logger.error("onMessage 数值类型原始数据计算，原始数据站点编码[" + rawStcd + "]，列名[" + rawColumnCode + "]，对应点号编码[" + pointid
                                                            + "]，时段类型[" + pointtmseg + "]，计算时间段[" + QmsTimeUtil.format(regularBeginTime, pointtmseg) + "]-[" + QmsTimeUtil.format(regularEndTime, pointtmseg)
                                                            + "]，点号计算结果失败，" + calcResult.getMsg());
                                                } else {
                                                    //计算成功
                                                    logger.info("onMessage 数值类型原始数据计算，原始数据站点编码[" + rawStcd + "]，列名[" + rawColumnCode + "]，对应点号编码[" + pointid
                                                            + "]，时段类型[" + pointtmseg + "]，计算时间段[" + QmsTimeUtil.format(regularBeginTime, pointtmseg) + "]-[" + QmsTimeUtil.format(regularEndTime, pointtmseg)
                                                            + "]，点号计算成功，应有数量[" + calcResult.getDueCount() + "]，实有数量[" + calcResult.getActualCount() + "]，计算出的点号数据条数[" + calcResult.getDatas().size() + "]");
                                                    if (calcSaveResultDto.getSaveResult() == null) {
                                                        //计算出的点号保存结果为null
                                                        logger.error("onMessage 数值类型原始数据计算，原始数据站点编码[" + rawStcd + "]，列名[" + rawColumnCode + "]，对应点号编码[" + pointid
                                                                + "]，时段类型[" + pointtmseg + "]，计算时间段[" + QmsTimeUtil.format(regularBeginTime, pointtmseg) + "]-[" + QmsTimeUtil.format(regularEndTime, pointtmseg)
                                                                + "]，点号计算保存结果对象为null");
                                                    } else {
                                                        QmsPointDataManageResultDto saveResult = calcSaveResultDto.getSaveResult();
                                                        if (saveResult.isSuccess() == false) {
                                                            //保存失败
                                                            logger.error("onMessage 数值类型原始数据计算，原始数据站点编码[" + rawStcd + "]，列名[" + rawColumnCode + "]，对应点号编码[" + pointid
                                                                    + "]，时段类型[" + pointtmseg + "]，计算时间段[" + QmsTimeUtil.format(regularBeginTime, pointtmseg) + "]-[" + QmsTimeUtil.format(regularEndTime, pointtmseg)
                                                                    + "]，点号计算结果保存失败，" + saveResult.getMsg());
                                                        } else {
                                                            logger.info("onMessage 数值类型原始数据计算，原始数据站点编码[" + rawStcd + "]，列名[" + rawColumnCode + "]，对应点号编码[" + pointid
                                                                    + "]，时段类型[" + pointtmseg + "]，计算时间段[" + QmsTimeUtil.format(regularBeginTime, pointtmseg) + "]-[" + QmsTimeUtil.format(regularEndTime, pointtmseg)
                                                                    + "]，点号计算结果保存成功，受影响条数[" + saveResult.getAffectCount() + "]");
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * 根据指定的原始数据表编码获取对应的数据库连接；如果在保存的数据库连接Map中已有对应返回已有，如果没有调用platform接口获取后缓存到Map中
     *
     * @param tableCode 原始数据表编码
     * @return qc.module.platform.dto.db.DBConnectionDto
     * @author QuCheng Tech
     * @since 2025/11/1
     */
    DBConnectionDto getTableConnection(String tableCode) throws QCPromptException {
        if (StringUtils.isNotBlank(tableCode)) {
            if (tableCodeConnectionMap == null)
                tableCodeConnectionMap = new HashMap<>();

            //如果根据key存在已有的数据库连接，直接返回
            if (tableCodeConnectionMap.size() > 0x0 && tableCodeConnectionMap.containsKey(tableCode))
                return tableCodeConnectionMap.get(tableCode);

            //根据key获取不到已有的数据库连接，调用platform获取数据库连接信息
            DBConnectionDto tableConnection = restTemplatePlatform.getDbTableConnectionInfo(tableCode);
            if (tableConnection != null) {
                tableCodeConnectionMap.put(tableCode, tableConnection);

                return tableConnection;
            }
        }

        return null;
    }
}